package diff.viewer;

import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.GeneralPath;
import java.util.Map;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;

/**
 * @author WL
 */
public class DiffSplitPaneDivider extends BasicSplitPaneDivider
{
    private DiffPaneManager manager;
    private static Map renderingHints = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty(
                    "awt.font.desktophints"));

    
    public DiffSplitPaneDivider(BasicSplitPaneUI splitPaneUI) 
    {
        super(splitPaneUI);
    }
    
    public void setManager(DiffPaneManager manager)
    {
        this.manager = manager;
    }
    
    public void paint(Graphics gr) {
        if (manager == null)
            return;
        
        DiffPane diffPane = manager.getDiffPane();
        
        if (diffPane == null)
            return;
        
        Graphics2D g = (Graphics2D) gr.create();
        Rectangle clip = g.getClipBounds();

        g.setColor(getBackground());
        g.fillRect(clip.x, clip.y, clip.width, clip.height);

        Rectangle rightView = diffPane.getScrollPane2().getViewport().getViewRect();
        Rectangle leftView = diffPane.getScrollPane1().getViewport().getViewRect();

        int editorsOffset = 0;//viewer.getEditorPane2().getLocation().y + viewer.getEditorPane2().getInsets().top;

        int rightOffset = -rightView.y + editorsOffset;
        int leftOffset = -leftView.y + editorsOffset;

        if (renderingHints != null)
            g.addRenderingHints(renderingHints);
        
        if (clip.y < editorsOffset)
            g.setClip(clip.x, editorsOffset, clip.width, clip.height);

        int rightY = getWidth() - 1;

        g.setColor(Color.LIGHT_GRAY);
        g.drawLine(0, clip.y, 0, clip.height);
        g.drawLine(rightY, clip.y, rightY, clip.height);

        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        if (manager.getDecorations() == null)
            return;
        
        for (DecoratedDifference dd : manager.getDecorations()) {
            g.setColor(DiffColor.getColor(dd.getDiff()));
            if (dd.getBottomLeft() == -1) {
                paintMatcher(g, DiffColor.getColor(dd.getDiff()), 0, rightY,
                        dd.getTopLeft() + leftOffset, dd.getTopRight() + rightOffset, 
                        dd.getBottomRight() + rightOffset, dd.getTopLeft() + leftOffset);
            } else if (dd.getBottomRight() == -1) {
                paintMatcher(g, DiffColor.getColor(dd.getDiff()), 0, rightY,
                        dd.getTopLeft() + leftOffset, dd.getTopRight() + rightOffset, 
                        dd.getTopRight() + rightOffset, dd.getBottomLeft() + leftOffset);
            } else {
                paintMatcher(g, DiffColor.getColor(dd.getDiff()), 0, rightY,
                        dd.getTopLeft() + leftOffset, dd.getTopRight() + rightOffset, 
                        dd.getBottomRight() + rightOffset, dd.getBottomLeft() + leftOffset);
            }
        }
    }

    private void paintMatcher(Graphics2D g, Color fillClr, 
        int leftX, int rightX, int upL, int upR, int doR, int doL) {
        int topY = Math.min(upL, upR), bottomY = Math.max(doL, doR);
        // try rendering only curves in viewable area
        if (!g.hitClip(leftX, topY, rightX - leftX, bottomY - topY)) {
            return;
        }
        CubicCurve2D upper = new CubicCurve2D.Float(leftX, upL,
                (rightX -leftX)*.3f, upL,
                (rightX -leftX)*.7f, upR,
                rightX, upR);
        CubicCurve2D bottom = new CubicCurve2D.Float(rightX, doR,
                (rightX - leftX)*.7f, doR,
                (rightX -leftX)*.3f, doL,
                leftX, doL);
        GeneralPath path = new GeneralPath();
        path.append(upper, false);
        path.append(bottom, true);
        path.closePath();
        g.setColor(fillClr);
        g.fill(path);
        g.setColor(DiffColor.colorBorder);
        g.draw(upper);
        g.draw(bottom);
    }
}
